package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"os"
	_ "os/exec"
	"strconv"
	"strings"
	_ "syscall"
	"time"
)

const (
	icmpv4EchoRequest = 8
	icmpv4EchoReply   = 0
	icmpv6EchoRequest = 128
	icmpv6EchoReply   = 129
)

type ICMP struct {
	Type        uint8
	Code        uint8
	Checksum    uint16
	Identifier  uint16
	SequenceNum uint16
}

func main() {
	// 获取本地ip地址.方法1
	//	bash, err := exec.LookPath("bash")
	//	if err != nil {
	//		panic(err)
	//	}
	//
	//	args := []string{"bash", "localip.sh"}
	//	env := os.Environ()
	//
	//	execErr := syscall.Exec(bash, args, env)
	//	if execErr != nil {
	//		panic(execErr)
	//	}

	//	fmt.Println("after syscall exec") // this code will not run after
	// syscall.Exec()

	arg_num := len(os.Args)
	if arg_num < 1 {
		fmt.Printf("Error!!\nPlease use super user!\n")
		return
	}

	//获取本地ip地址.方法2 :

	conn, err := net.Dial("tcp", "www.baidu.com:80")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer conn.Close()
	localip := strings.Split(conn.LocalAddr().String(), ":")[0]

	splitString := strings.Split(localip, ".")
	fmt.Println(splitString)
	host, err := strconv.Atoi(splitString[3])
	if err != nil {
		panic(err)
	}
	fmt.Printf("host :%v \n", host)

	var ipSlice []string

	for i := 1; i < 255; i++ {
		netAddr := fmt.Sprintf("%s.%s.%s.%d", splitString[0], splitString[1], splitString[2], i)
		fmt.Printf("address :%s\n", netAddr)
		if Ping(netAddr){
			ipSlice = append(ipSlice,netAddr)
		}
	}

	fmt.Printf("Connect ip address is :%v\n",ipSlice)


}

func Ping(addr string) bool {

	c, err := net.Dial("ip4:icmp", addr)
	if err != nil {
		fmt.Printf("dial %v\n fail %s!", addr, err)
		return false
	}
	//c.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond))
	defer c.Close()

	var icmp ICMP
	icmp.Type = icmpv4EchoRequest
	icmp.Code = 0
	icmp.Checksum = 0
	icmp.Identifier = 0
	icmp.SequenceNum = 0

	var buffer bytes.Buffer
	binary.Write(&buffer, binary.BigEndian, icmp)

	icmp.Checksum = Checksum(buffer.Bytes())
	buffer.Reset()
	binary.Write(&buffer, binary.BigEndian, icmp)
//	fmt.Printf("icmp :%v  buffer :%v\n", icmp, buffer)

//	fmt.Printf("\n 正在 ping %s,具有0字节的数据\n", addr)
	recv := make([]byte, 1024)


	recvFlag := false

	for i := 4; i > 0; i-- {

		if _, err := c.Write(buffer.Bytes()); err != nil {
			fmt.Println(err.Error)
		}

		t_start := time.Now()
		c.SetReadDeadline(time.Now().Add(time.Millisecond * 500))

		_, err := c.Read(recv)
		if err != nil {
//			fmt.Printf("请求超时%s\n", err)
			continue
		}

		t_end := time.Now()
		dur := t_end.Sub(t_start).Nanoseconds() / 1e6
		fmt.Printf("来自%s 的回复: time = %d ms \n", addr, dur)
		recvFlag = true 
	}

	return recvFlag 
}

func Checksum(data []byte) uint16 {
	var sum uint32
	var length int = len(data)
	var index int

	for length > 1 {
		sum += uint32(data[index])<<8 + uint32(data[index+1])
		index += 2
		length -= 2
	}

	for length > 0 {
		sum += uint32(data[index])
	}
	sum += (sum >> 16)
	return uint16(^sum)

}
